# Copyright (C) 2009, Mathias Gyllengahm
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.

import cwiid
import sys
import traceback
import time
import wx
import wiidrumsgui
import getopt
import alsaseq

from dtypes import WIIMOTE, NUNCHUK, BALANCE
from logfilehandler import LogfileHandler
import dataprocessor

wiimote = None
running = True
frame = None
logfilehandler = None
processor = dataprocessor.Processor()
bboard = None

#------------------------------------------------------------
def displayUsage():
    print "python wiidrums.py"
    print " [-h | --help]                print help"
    print " [-l | --log ] <filename>     Log events to file"
    print " [-r | --replay ] <filename>  Replay logfile"
    print " [-b | --btaddr ] <filename>  Bluetooth address for wiimote"

#------------------------------------------------------------
def main():
    global wiimote, frame, logfilehandler, bboard

    opts, args = getopt.getopt(sys.argv[1:], 'h:l:r:b:s', longopts=['help','log=','replay=','btaddr','scale'])
    replay = False
    btaddr = None
    scale = None

    for o, a in opts:
        if o == "-l" or o == "--log": # Log to file
            logfilehandler = LogfileHandler(a)
            logfilehandler.startlogging()
        elif o == "-r" or o == "--replay": # Replay from file
            logfilehandler = LogfileHandler(a)
            replay = True
            print "logfile="+ a
        elif o == "-h" or o == "--help": # Help
            displayUsage()
            sys.exit(0)
        elif o == "-b" or o == "--btaddr":
            btaddr = a
        elif o == "-s" or o == "--scale":
            scale = a
        else:
            assert False, "Unhandled option: " + str(o) + ":" +str(a)

    # Midi bridge stuff
    alsaseq.client( 'wiidrums', 0, 1, False )
    alsaseq.connectto( 0, 129, 0 )  # Currently hardcoded alsa connection... Hmmm...
    alsaseq.start()
    
    #while True:
    #    alsaseq.output( (6, 1, 0, 1, (0, 0), (0, 0), (0, 0), (0, 42, 127, 0, 100)) )
    #    time.sleep(0.5)

    # wx gui stuff
    app = wx.PySimpleApp(0)
    wx.InitAllImageHandlers()
    frame = wiidrumsgui.MyFrame1(None, -1, "")
    app.SetTopWindow(frame)
    frame.Show()

    if not replay:
        try: 
            print 'Put Wiimote in discoverable mode now (press 1+2)...'
            if btaddr != None:
                print "Connecting to " + str(btaddr)
                wiimote = cwiid.Wiimote(btaddr)
            else:
                wiimote = cwiid.Wiimote()

            if scale != None:
                print "Connecting to balance board..." + str(scale)
                bboard = cwiid.Wiimote(scale)
                bboard.rpt_mode = cwiid.RPT_BALANCE


            wiimote.mesg_callback = cwiidcallback
            rpt_mode = cwiid.RPT_BTN | cwiid.RPT_EXT | cwiid.RPT_ACC
            print "Rpt mode: " + str(rpt_mode)
            wiimote.rpt_mode = rpt_mode
            wiimote.enable(cwiid.FLAG_MESG_IFC)
        except:
            traceback.print_exc(file=sys.stdout)

    try:
        if replay:
            logfilehandler.replayfile(callback)
        app.MainLoop()
    except KeyboardInterrupt:
        pass
    except:
        traceback.print_exc(file=sys.stdout)
        
    if wiimote != None:
        wiimote.close()
    if logfilehandler != None:
        logfilehandler.stoplopping()
    if bboard != None:
        bboard.close()

    try:
        app.MainLoop()
    except KeyboardInterrupt:
        pass
    except:
            traceback.print_exc(file=sys.stdout)
#------------------------------------------------------------
def callback(type, data):
    global processor
    
    hit = processor.process(type, data)
    # 36 BD
    # 38 Snare
    # 43 CHH
    # 42 Closed hihat
    notes = []
    if type == NUNCHUK:
        notes.append(38) # Snare
    elif type == WIIMOTE:
        if data[3] & cwiid.BTN_A:
            notes.append(38)
        elif data[3] & cwiid.BTN_MINUS:
            notes.append(49)
        else:
            notes.append(42)
        if data[3] & cwiid.BTN_B:
            notes.append(36)
    elif type == BALANCE:
        notes.append(36)
    if hit[0] != -1:
        #velo = (hit[1] - hit[0]) / 255.0 * 127.0
        velo = (hit[1] - hit[0]) / 170.0 * 127.0
        v = int(velo)
        if v > 127:
            v = 127
        print str(hit[1]) + ":" + str(hit[0]) + "=" + str(velo)
        for note in notes:
            alsaseq.output( (6, 1, 0, 1, (0, 0), (0, 0), (0, 0), (0, note, v, 0, 100)) )
    #if type == WIIMOTE:
    if type == WIIMOTE:
        pass
        #print str(type) + ":" + str(data) + " " + str(hit)
        wx.MutexGuiEnter()
        try:
            frame.label_maccx.SetLabel("ACCX: " + str(data[0]))
            frame.label_maccy.SetLabel("ACCY: " + str(data[1]))
            frame.label_maccz.SetLabel("ACCZ: " + str(data[2]))
            frame.label_mbtn.SetLabel("BTN:  " + str(data[3]))

        except:
            traceback.print_exc(file=sys.stdout)
        wx.MutexGuiLeave()
    elif type == NUNCHUK:
        pass
        #print str(type) + ":" + str(data) + " " + str(hit)
        wx.MutexGuiEnter()
        try:
            frame.label_naccx.SetLabel("ACCX: " + str(data[0]))
            frame.label_naccy.SetLabel("ACCY: " + str(data[1]))
            frame.label_naccz.SetLabel("ACCZ: " + str(data[2]))
            frame.label_nbtn.SetLabel("BTN:  " + str(data[3]))
        except:
            traceback.print_exc(file=sys.stdout)
        wx.MutexGuiLeave()
    elif type == BALANCE:
        pass
        #print "Balance!" + str(data)
        
    
#------------------------------------------------------------
def cwiidcallback(mesg_list):
    global wiimote, frame, logfilehandler, bboard
    try:
        event = None
        nevent = None
        bevent = None

        mesg = mesg_list[0] # Only checking one of them
        #for mesg in mesg_list:
        if mesg[0] == cwiid.MESG_ACC:
            event = []
            event.append(mesg[1][cwiid.X])
            event.append(mesg[1][cwiid.Y])
            event.append(mesg[1][cwiid.Z])
            event.append(wiimote.state['buttons'])

            if wiimote.state.has_key('nunchuk'):
                nevent = []
                nevent.append(wiimote.state['nunchuk']['acc'][cwiid.X])
                nevent.append(wiimote.state['nunchuk']['acc'][cwiid.Y])
                nevent.append(wiimote.state['nunchuk']['acc'][cwiid.Z])
                nevent.append(wiimote.state['nunchuk']['buttons'])

            if bboard != None:
                bevent = []
                bevent.append(bboard.state['balance']['left_bottom']) #lb, rt, rb, lt
                bevent.append(bboard.state['balance']['right_top']) #lb, rt, rb, lt
                bevent.append(bboard.state['balance']['right_bottom']) #lb, rt, rb, lt
                bevent.append(bboard.state['balance']['left_top']) #lb, rt, rb, lt

            if logfilehandler != None:
                if event != None:
                    logfilehandler.event(WIIMOTE, event)
                if nevent != None:
                    logfilehandler.event(NUNCHUK, nevent)
                if bevent != None:
                    logfilehandler.event(BALANCE, bevent)

            if event != None:
                callback(WIIMOTE, event)
            if nevent != None:
                callback(NUNCHUK, nevent)
            if bevent != None:
                callback(BALANCE, bevent)

        #if mesg[0] == cwiid.MESG_BALANCE:
        #    print "BALANCE: " + str(mesg)

    except:
        traceback.print_exc(file=sys.stdout)
#------------------------------------------------------------
if __name__ == '__main__':
    main()

